Generate a grab broken event when appropriate. Fixes bug #346603, patch
authorRichard Hult <richard@imendio.com>
Fri, 7 Jul 2006 20:19:22 +0000 (20:19 +0000)
committerRichard Hult <rhult@src.gnome.org>
Fri, 7 Jul 2006 20:19:22 +0000 (20:19 +0000)
2006-07-07  Richard Hult  <richard@imendio.com>

* gdk/quartz/gdkevents-quartz.c: Generate a grab broken event when
appropriate. Fixes bug #346603, patch from Dave Vasilevsky.

* gdk/quartz/gdkevents-quartz.c:
* gdk/quartz/gdkkeys-quartz.c:
* gdk/quartz/gdkprivate-quartz.c: Another patch from Dave Vasilevsky,
fixes bug #346605. Makes modifier key events being sent properly.

ChangeLog
ChangeLog.pre-2-10
gdk/quartz/gdkevents-quartz.c
gdk/quartz/gdkkeys-quartz.c
gdk/quartz/gdkprivate-quartz.h

index 6a0048f52011ecd1e5bb0b9e4d40d64a4a0f4461..10fe7ce72d911c4724123804271b895f92efbaa7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2006-07-07  Richard Hult  <richard@imendio.com>
+
+       * gdk/quartz/gdkevents-quartz.c: Generate a grab broken event when
+       appropriate. Fixes bug #346603, patch from Dave Vasilevsky.
+       
+       * gdk/quartz/gdkevents-quartz.c:
+       * gdk/quartz/gdkkeys-quartz.c:
+       * gdk/quartz/gdkprivate-quartz.c: Another patch from Dave Vasilevsky,
+       fixes bug #346605. Makes modifier key events being sent properly.
+
 2006-07-07  Michael Natterer  <mitch@imendio.com>
 
        * gtk/gtkrc.c
index 6a0048f52011ecd1e5bb0b9e4d40d64a4a0f4461..10fe7ce72d911c4724123804271b895f92efbaa7 100644 (file)
@@ -1,3 +1,13 @@
+2006-07-07  Richard Hult  <richard@imendio.com>
+
+       * gdk/quartz/gdkevents-quartz.c: Generate a grab broken event when
+       appropriate. Fixes bug #346603, patch from Dave Vasilevsky.
+       
+       * gdk/quartz/gdkevents-quartz.c:
+       * gdk/quartz/gdkkeys-quartz.c:
+       * gdk/quartz/gdkprivate-quartz.c: Another patch from Dave Vasilevsky,
+       fixes bug #346605. Makes modifier key events being sent properly.
+
 2006-07-07  Michael Natterer  <mitch@imendio.com>
 
        * gtk/gtkrc.c
index 9f72be90b65d4d471b2cf59d3f6409bbadc672fe..d533d353cf5cc882fb777beadb2cbae8efbde996 100644 (file)
@@ -333,6 +333,28 @@ gdk_event_get_graphics_expose (GdkWindow *window)
   return NULL;
 }
 
+static void
+generate_grab_broken_event (GdkWindow *window,
+                           gboolean   keyboard,
+                           gboolean   implicit,
+                           GdkWindow *grab_window)
+{
+  if (!GDK_WINDOW_DESTROYED (window))
+    {
+      GdkEvent event;
+  
+      event.type = GDK_GRAB_BROKEN;
+      event.grab_broken.window = window;
+      event.grab_broken.send_event = 0;
+      event.grab_broken.keyboard = keyboard;
+      event.grab_broken.implicit = implicit;
+      event.grab_broken.grab_window = grab_window;
+      
+      gdk_event_put (&event);
+    }
+}
+
+
 GdkGrabStatus
 gdk_keyboard_grab (GdkWindow  *window,
                   gint        owner_events,
@@ -342,7 +364,11 @@ gdk_keyboard_grab (GdkWindow  *window,
   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
 
   if (_gdk_quartz_keyboard_grab_window)
-    gdk_keyboard_ungrab (time);
+    {
+      generate_grab_broken_event (_gdk_quartz_keyboard_grab_window,
+                                 TRUE, FALSE, window);
+      g_object_unref (_gdk_quartz_keyboard_grab_window);
+    }
 
   _gdk_quartz_keyboard_grab_window = g_object_ref (window);
   keyboard_grab_owner_events = owner_events;
@@ -454,10 +480,15 @@ gdk_pointer_grab (GdkWindow    *window,
 
   if (_gdk_quartz_pointer_grab_window)
     {
-      if (!pointer_grab_implicit)
-       return GDK_GRAB_ALREADY_GRABBED;
+      if (_gdk_quartz_pointer_grab_window == window && !pointer_grab_implicit)
+        return GDK_GRAB_ALREADY_GRABBED;
       else
-       pointer_ungrab_internal (TRUE);
+        {
+          if (_gdk_quartz_pointer_grab_window != window)
+            generate_grab_broken_event (_gdk_quartz_pointer_grab_window,
+                                       FALSE, pointer_grab_implicit, window);
+          pointer_ungrab_internal (TRUE);
+        }
     }
 
   return pointer_grab_internal (window, owner_events, event_mask, 
@@ -680,9 +711,18 @@ get_event_mask_from_ns_event (NSEvent *nsevent)
        return mask;
       }
     case NSKeyDown:
-      return GDK_KEY_PRESS_MASK;
     case NSKeyUp:
-      return GDK_KEY_RELEASE_MASK;
+    case NSFlagsChanged:
+      {
+        GdkEventType type = _gdk_quartz_key_event_type (nsevent);
+        switch (type)
+          {
+            case GDK_KEY_PRESS:   return GDK_KEY_PRESS_MASK;
+            case GDK_KEY_RELEASE: return GDK_KEY_RELEASE_MASK;
+            case GDK_NOTHING:     return 0;
+            default: g_assert_not_reached ();
+          }
+      }
     default:
       g_assert_not_reached ();
     }
@@ -1137,6 +1177,7 @@ find_window_for_event (NSEvent *nsevent, gint *x, gint *y)
 
     case NSKeyDown:
     case NSKeyUp:
+    case NSFlagsChanged:
       {
        GdkWindow *keyboard_window;
        GdkEventMask event_mask;
@@ -1274,24 +1315,11 @@ create_scroll_event (GdkWindow *window, NSEvent *nsevent, GdkScrollDirection dir
 }
 
 static GdkEvent *
-create_key_event (GdkWindow *window, NSEvent *nsevent)
+create_key_event (GdkWindow *window, NSEvent *nsevent, GdkEventType type)
 {
-  GdkEventType event_type;
   GdkEvent *event;
 
-  switch ([nsevent type]) 
-    {
-    case NSKeyDown:
-      event_type = GDK_KEY_PRESS;
-      break;
-    case NSKeyUp:
-      event_type = GDK_KEY_RELEASE;
-      break;
-    default:
-      g_assert_not_reached ();
-    }
-
-  event = gdk_event_new (event_type);
+  event = gdk_event_new (type);
   event->key.window = window;
   event->key.time = get_event_time (nsevent);
   event->key.state = get_keyboard_modifiers_from_nsevent (nsevent);
@@ -1305,6 +1333,12 @@ create_key_event (GdkWindow *window, NSEvent *nsevent)
                                       &event->key.keyval,
                                       NULL, NULL, NULL);
 
+  GDK_NOTE(EVENTS,
+    g_message ("key %s:\t\twindow: %p  key: %12s  %d",
+         type == GDK_KEY_PRESS ? "press" : "release",
+         event->key.window,
+         event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
+         event->key.keyval));
   return event;
 }
 
@@ -1425,11 +1459,17 @@ gdk_event_translate (NSEvent *nsevent)
       }
     case NSKeyDown:
     case NSKeyUp:
-      event = create_key_event (window, nsevent);
-      append_event (event);
-      return TRUE;
-      break;
-
+    case NSFlagsChanged:
+      {
+        GdkEventType type = _gdk_quartz_key_event_type (nsevent);
+        if (type == GDK_NOTHING)
+          return FALSE;
+        
+        event = create_key_event (window, nsevent, type);
+        append_event (event);
+        return TRUE;
+        break;
+      }
     default:
       NSLog(@"Untranslated: %@", nsevent);
     }
index 0ce4c92184078f2a0d901154e2c801ce782509c6..f3bc8283e8268684c03f49e1caa5c3f237074ee7 100644 (file)
@@ -52,6 +52,7 @@
 #include <config.h>
 
 #include <Carbon/Carbon.h>
+#include <AppKit/NSEvent.h>
 #include "gdk.h"
 #include "gdkkeysyms.h"
 
@@ -102,30 +103,32 @@ macroman2ucs (unsigned char c)
 const static struct {
   guint keycode;
   guint keyval;
+  unsigned int modmask; /* So we can tell when a mod key is pressed/released */
 } known_keys[] = {
-  {  55, GDK_Meta_L },
-  {  56, GDK_Shift_L },
-  {  57, GDK_Caps_Lock },
-  {  58, GDK_Alt_L },
-  {  59, GDK_Control_L },
-  {  60, GDK_Shift_R },
-  {  61, GDK_Alt_R },
-  {  62, GDK_Control_R },
-  { 122, GDK_F1 },
-  { 120, GDK_F2 },
-  {  99, GDK_F3 },
-  { 118, GDK_F4 },
-  {  96, GDK_F5 },
-  {  97, GDK_F6 },
-  {  98, GDK_F7 },
-  { 100, GDK_F8 },
-  { 101, GDK_F9 },
-  { 109, GDK_F10 },
-  { 103, GDK_F11 },
-  { 111, GDK_F12 },
-  { 105, GDK_F13 },
-  { 107, GDK_F14 },
-  { 113, GDK_F15 },
+  {  54, GDK_Meta_R,    NSCommandKeyMask },
+  {  55, GDK_Meta_L,    NSCommandKeyMask },
+  {  56, GDK_Shift_L,   NSShiftKeyMask },
+  {  57, GDK_Caps_Lock, NSAlphaShiftKeyMask },
+  {  58, GDK_Alt_L,     NSAlternateKeyMask },
+  {  59, GDK_Control_L, NSControlKeyMask },
+  {  60, GDK_Shift_R,   NSShiftKeyMask },
+  {  61, GDK_Alt_R,     NSAlternateKeyMask },
+  {  62, GDK_Control_R, NSControlKeyMask },
+  { 122, GDK_F1, 0 },
+  { 120, GDK_F2, 0 },
+  {  99, GDK_F3, 0 },
+  { 118, GDK_F4, 0 },
+  {  96, GDK_F5, 0 },
+  {  97, GDK_F6, 0 },
+  {  98, GDK_F7, 0 },
+  { 100, GDK_F8, 0 },
+  { 101, GDK_F9, 0 },
+  { 109, GDK_F10, 0 },
+  { 103, GDK_F11, 0 },
+  { 111, GDK_F12, 0 },
+  { 105, GDK_F13, 0 },
+  { 107, GDK_F14, 0 },
+  { 113, GDK_F15, 0 },
 };
 
 const static struct {
@@ -574,3 +577,41 @@ gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
 
   return TRUE;
 }
+
+/* What sort of key event is this? Returns one of
+ * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
+ */
+GdkEventType _gdk_quartz_key_event_type (NSEvent *event)
+{
+  unsigned short keycode;
+  unsigned int flags;
+  int i;
+  
+  switch ([event type])
+    {
+      case NSKeyDown: return GDK_KEY_PRESS;
+      case NSKeyUp:   return GDK_KEY_RELEASE;
+      case NSFlagsChanged: break; /* Continue... */
+      default: g_assert_not_reached ();
+    }
+  
+  /* For flags-changed events, we have to find the special key that caused the
+   * event, and see if it's in the modifier mask. */
+  keycode = [event keyCode];
+  flags = [event modifierFlags];
+  
+  for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
+    {
+      if (known_keys[i].keycode == keycode)
+          {
+                if (flags & known_keys[i].modmask)
+                  return GDK_KEY_PRESS;
+                else
+                  return GDK_KEY_RELEASE;
+          }
+       }
+  
+  /* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
+   * events for no good reason. Ignore them! */
+  return GDK_NOTHING;
+}
index 177d0fbb7f0b38bf62eec825494fd808b712c693..960844d3b5b8f7277de0892c09f901d5835388e2 100644 (file)
@@ -122,6 +122,8 @@ GdkImage *_gdk_quartz_copy_to_image (GdkDrawable *drawable,
 
 void _gdk_quartz_send_map_events (GdkWindow *window);
 
+GdkEventType _gdk_quartz_flags_changed_is_press (NSEvent *event);
+
 extern GdkWindow *_gdk_quartz_keyboard_grab_window;
 extern GdkWindow *_gdk_quartz_pointer_grab_window;